package org.bing.engine.container.jetty.launcher;

import java.io.File;
import java.util.ArrayList;
import java.util.List;

import org.bing.engine.container.jetty.helper.TemplateHelper;
import org.bing.engine.controller.helper.UrlBuilder;
import org.bing.engine.controller.lifecycle.GeneralContainerLifecycle;
import org.bing.engine.core.domain.Application;
import org.bing.engine.core.domain.Container;
import org.bing.engine.core.domain.ContainerInstance;
import org.bing.engine.core.domain.ContainerSetting;
import org.bing.engine.utility.helper.FileHelper;
import org.bing.engine.utility.helper.GuidGenerator;
import org.bing.engine.utility.helper.JdkHelper;
import org.bing.engine.utility.helper.StringHelper;
import org.bing.engine.utility.helper.ThreadHelper;
import org.bing.engine.utility.helper.UrlHelper;

public class JettyLifecycle extends GeneralContainerLifecycle {

    @Override
    public synchronized ContainerInstance startup(ContainerSetting setting, Application application) {
        String globalId = guid();
        ContainerInstance result = new ContainerInstance(globalId);
        result.setApplication(application);
        List<String> args = new ArrayList<String>();

        // locate conf location
        String jettyBase = getJettyBase(setting);
        String engineBase = configuration.getEngineBase();

        // format: java ${jvmargs} -cp ${classpath} ${mainclass} ${parameters}
        args.add(JdkHelper.findJavaBin()); // ex:/opt/JDK160/jre/bin/java
        // jvm args: -Xmx256m -Xmx128m
        if (setting.getJvmargs() != null) {
            String[] jvms = setting.getJvmargs().split(" ");
            if (jvms != null && jvms.length > 0) {
                for (int i = 0; i < jvms.length; i++) {
                    if (!StringHelper.isBlank(jvms[i])) {
                        args.add(jvms[i]);
                    }
                }
            }
        }

        // system property
        args.add("-D" + result.getFullGlobalId());

        // write setting to jetty.xml
        String confFile = jettyBase + "conf" + File.separator + "jetty.xml";
        // TemplateHelper.transform(setting.getSetting(), conf, args, result);
        String lastFile = TemplateHelper.transform(engineBase, jettyBase, setting.getSetting(), args, result);
        FileHelper.write(lastFile, confFile);
        // ready application file to deploy directory
        FileHelper.writeUrlToFile(application.getLocation(), result.getDeployLocation());

        // system classpath
        args.add("-classpath");
        args.add(getJettyClasspath(setting));
        // main class
        args.add("org.eclipse.jetty.xml.XmlConfiguration");
        // main args
        args.add(confFile);

        // run cmd by processManager
        logger.info("CmdLine:" + args);
        process.start(globalId, jettyBase, args.toArray(new String[args.size()]));
        if (globalId == null) {
            throw new RuntimeException("Cant start jetty processManager!");
        }
        result.setSetting(setting);
        return result;
    }

    @Override
    public synchronized String showCmdLine(ContainerSetting setting) {
        // format: java ${jvmargs} -cp ${classpath} ${mainclass} ${parameters}
        StringBuilder sb = new StringBuilder(256);
        sb.append(JdkHelper.findJavaBin()).append(" "); // ex:/home/admin/JDK160/jre/bin/java
        sb.append(setting.getJvmargs()).append(" ");
        sb.append("-classpath ").append(getJettyClasspath(setting));
        sb.append("org.eclipse.jetty.xml.XmlConfiguration").append(" ");
        sb.append(getJettyBase(setting)).append("conf").append(File.separator).append("jetty.xml");
        return sb.toString();
    }

    @Override
    public synchronized void shutdown(ContainerInstance inst) {
        if (process.exists(inst.getGlobalId())) {
            process.destroy(inst.getGlobalId());
        } else {
            String url = UrlBuilder.build(inst, "shutdown");
            for (int i = 0; i < 5; i++) { 
                if (UrlHelper.isAlive(url, 3, 300)) {
                    try {
                        UrlHelper.call(url);
                    } catch (Exception e) {
                        // ignore, try next
                        ThreadHelper.sleep(500);
                    }
                } else {
                    continue;
                } 
            }
        }
        instance.delete(inst);
        // TODO impl alone child manage, ex ContainerInstance
    }

    private String getJettyClasspath(ContainerSetting setting) {
        Container container = setting.getContainer();
        StringBuilder sb = new StringBuilder(256);
        String base = configuration.getContainerBase() + container.getName() + "-" + container.getVersion() + File.separator;
        File file = new File(base + "lib");
        if (file.exists()) {
            File[] files = file.listFiles();
            if (files != null && files.length > 0) {
                for (int i = 0; i < files.length; i++) {
                    File f = files[i];
                    String path = f.getPath();
                    if (path.endsWith(".jar")) {
                        sb.append(path).append(File.pathSeparator);
                    }
                }
            }
        }
        // add statistic to classpath
        sb.append(configuration.getEngineBase() + "lib" + File.separator + "x-engine-container-statistic.jar");
        return sb.toString();
    }

    private String getJettyBase(ContainerSetting setting) {
        String base = configuration.getWorkDirectory();
        Container container = setting.getContainer();
        base += container.getName() + "-" + container.getVersion();
        String home = base + "-" + GuidGenerator.random(5) + File.separator;
        while (new File(home).exists()) {
            home = base + GuidGenerator.random(5) + File.separator;
        }
        return home;
    }
}
